package com.suxin.plugin.intergration.factory.process.post;

import com.suxin.plugin.intergration.factory.PluginRegistryInfo;
import com.suxin.plugin.intergration.factory.SpringBeanRegister;
import com.suxin.plugin.intergration.factory.process.pip.classs.group.ControllerGroup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.reactive.result.method.RequestMappingInfo;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author Tang
 * @classname PluginControllerPostProcessor
 * @description [  ]
 * @date 2022/7/23 14:49
 */
@Slf4j
public class PluginControllerPostProcessor implements PluginPostProcessor {

    private final ApplicationContext applicationContext;
    private final List<ControllerBeanWrapper> controllerBeanWrappers;

    /**
     * 注册controller映射
     */
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;
    private final SpringBeanRegister springBeanRegister;

    public PluginControllerPostProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.springBeanRegister = new SpringBeanRegister(this.applicationContext);
        this.requestMappingHandlerMapping = this.applicationContext.getBean(RequestMappingHandlerMapping.class);
        this.controllerBeanWrappers = new ArrayList<>(10);
    }

    @Override
    public void initialize() throws Exception {

    }

    @Override
    public void registry(List<PluginRegistryInfo> pluginRegistryInfos) throws Exception {
        for (PluginRegistryInfo pluginRegistryInfo : pluginRegistryInfos) {
            List<Class<?>> groupClasses = pluginRegistryInfo.getGroupClass().get(ControllerGroup.GROUP_ID);
            if(groupClasses == null || groupClasses.isEmpty()){
                continue;
            }
            for (Class<?> aClass : groupClasses) {
                ControllerBeanWrapper beanWrapper = registry(pluginRegistryInfo,aClass);
                controllerBeanWrappers.add(beanWrapper);
            }
        }
    }

    private ControllerBeanWrapper registry(PluginRegistryInfo pluginRegistryInfo, Class<?> aClass) throws Exception {
        log.info("注册Controller Bean...start...{}",aClass);
        ControllerBeanWrapper controllerBeanWrapper = new ControllerBeanWrapper(aClass);
        Method getMappingForMethod = ReflectionUtils.findMethod(aClass, "getMappingForMethod");
        // 获取controller bean
        String beanName = this.springBeanRegister.register(pluginRegistryInfo.getPluginId(), aClass);
        controllerBeanWrapper.setName(beanName);
        Object bean = this.applicationContext.getBean(beanName);
        controllerBeanWrapper.setBean(bean);
        Set<RequestMappingInfo> requestMappingInfoList = new HashSet<>(10);
        controllerBeanWrapper.setRequestMappingInfos(requestMappingInfoList);
        // 获取controller类下面的所有方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(aClass);
        for (Method method : methods) {
            if (havingRequestMapping(method)) {
                method.setAccessible(true);
                assert getMappingForMethod != null;
                // 获取 RequestMappingInfo
                RequestMappingInfo requestMappingInfo = (RequestMappingInfo)
                        getMappingForMethod.invoke(this.requestMappingHandlerMapping, method, aClass);
                // 注册controller
                this.requestMappingHandlerMapping.registerMapping(requestMappingInfo,bean,method);
                requestMappingInfoList.add(requestMappingInfo);
            }
        }
        log.info("注册Controller Bean...end...{}",aClass);
        return controllerBeanWrapper;
    }

    private boolean havingRequestMapping(Method method) {
        return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null;
    }

    @Override
    public void unRegistry(List<PluginRegistryInfo> pluginRegistryInfos) {

    }

    public static class ControllerBeanWrapper {
        private Class<?> beanClass;
        private Set<RequestMappingInfo> requestMappingInfos;
        private String name;
        private Object bean;

        public ControllerBeanWrapper(Class<?> beanClass) {
            this.beanClass = beanClass;
        }

        public Object getBean() {
            return bean;
        }

        public void setBean(Object bean) {
            this.bean = bean;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Class<?> getBeanClass() {
            return beanClass;
        }

        public void setBeanClass(Class<?> beanClass) {
            this.beanClass = beanClass;
        }

        public Set<RequestMappingInfo> getRequestMappingInfos() {
            return requestMappingInfos;
        }

        public void setRequestMappingInfos(Set<RequestMappingInfo> requestMappingInfos) {
            this.requestMappingInfos = requestMappingInfos;
        }
    }

}